package edu.hawaii.duedates;
import com.meterware.httpunit.GetMethodWebRequest;
import com.meterware.httpunit.HttpUnitOptions;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebForm;
import com.meterware.httpunit.WebLink;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebTable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session; 
import javax.mail.Transport; 
import javax.mail.internet.InternetAddress; 
import javax.mail.internet.MimeMessage; 
import java.util.Date; 
import java.util.Properties; 
import java.util.Timer;
import java.util.TimerTask;
/**
 * Due Date Bootstrap demonstrates simple use of httpunit to retrieve and parse a web page. 
 * 
 * @author Jeho Jung, Kaneshige Yasuyuki
 */
public class DueDates extends TimerTask {
  boolean sort = false;
  boolean within = false;
  boolean uhLibrary = false;
  boolean hsLibrary = false;
  boolean console = false;
  boolean email = false;
  String msgTxt = "";
  String[] param;
  private Double wakeupValue = 0.0;
  Hashtable<String, String> uhTable = new Hashtable<String, String>();
  Hashtable<String, String> hsTable = new Hashtable<String, String>();
  /**
   * Attempts to login to UH Manoa or Hawaii State Library system.  
   * 
   * @param id The UH user ID. 
   * @param lastName  The UH user's last name. 
   * @return The WebConversation instance after successful login. 
   * @throws Exception If login was not successful with these credentials. 
   */
  WebConversation loginToUhLibrary(String id, String lastName) throws Exception {
    String url = "http://uhmanoa.lib.hawaii.edu/cgi-bin/Pwebrecon.cgi?DB=local&PAGE=pbLogon";
    // UH Library website has bogus JavaScript code.
    HttpUnitOptions.setExceptionsThrownOnScriptError(false);
    // create the conversation object which will maintain state for us
    WebConversation conversation = new WebConversation();
    WebRequest request = new GetMethodWebRequest(url);
    WebResponse response = conversation.getResponse(request);
    WebForm form = response.getFormWithName("logonpage");
    form.setParameter("BC", id);
    form.setParameter("LN", lastName);
    form.submit();
    response = conversation.getCurrentPage();
    if (response.getText().contains("Sorry, Login unsuccessful")) {
      throw new Exception("Error while logging in to UH Library");
    }
    return conversation;
  }
  
  /**
   * Attempts to login to the Hawaii State Library System.
   * 
   * @param id The hawaii library id barcode.
   * @param password The password (last four digits of your phone number).
   * @return The WebConversation after logging in. 
   * @throws Exception If errors occur while logging in. 
   */
  private WebConversation loginToHawaiiStateLibrary(String id, String password) throws 
    Exception {
    try {
    String url = "http://www.librarieshawaii.org/";
    // Website has bogus JavaScript code.
    HttpUnitOptions.setExceptionsThrownOnScriptError(false);
    // create the conversation object which will maintain state for us
    WebConversation conversation = new WebConversation();
    WebRequest request = new GetMethodWebRequest(url);
    WebResponse response = conversation.getResponse(request);
    WebLink link = response.getLinkWith("My Account");
    link.click();
    response = conversation.getCurrentPage();
    WebForm form = response.getForms()[0];
    form.setParameter("sec1", "0011429495");
    form.setParameter("sec2", "3845");
    form.submit();
    return conversation;
    }
    catch (Exception e) {
      throw new Exception ("Error while logging in to Hawaii State Library", e);
    }
  }
  
  /**
   * Given a logged in user to the UH Library site, provides info about their library books. 
   * @param id The UH user ID. 
   * @param lastName  The UH user's last name.    
   * @return A String containing information about their books.
   * @throws Exception If problems occur parsing the site pages. 
   */
  public Hashtable<String, String> getUhInfo(String id, String lastName) throws Exception {
    Hashtable<String, String> bookInfo = new Hashtable<String, String>();
    String dueDateInfo = "";
    String eachBookInfo = "";
    try {
      WebConversation conversation = this.loginToUhLibrary(id, lastName);
      WebResponse response = conversation.getCurrentPage();      
      WebTable targetTable = null;
      if (response.getText().contains("You have no items checked out.")) {
        bookInfo.put("No Due Dates", "No items Checked Out");
        return bookInfo;
      }
      else {
        WebTable webTables[] = response.getTables();        
        for (WebTable table : webTables) {
          if (table.getText().contains("Renewed")) {
            targetTable = table;
          }
        }
        for (int i = 1; i < targetTable.getRowCount(); i++) {
            dueDateInfo = targetTable.getCellAsText(i, 2).substring(13);
            eachBookInfo = targetTable.getCellAsText(i, 0).substring(0,70) + "..."; 
            bookInfo.put(eachBookInfo, dueDateInfo);
        }
        return bookInfo;
      }
    }
    catch (Exception e) {
      throw new Exception("Error getting UH Book info", e);
    }
  }
  
  /**
   * Gets info from the Hawaii State Library site.
   * 
   * @param hiStateId The barcode number from the library card.
   * @param hiStatePassword The password (normally the last four digits of your phone number).
   * @return A string providing information about checked out books. 
   * @throws Exception If problems occur getting the information. 
   */
  public Hashtable<String, String> getHawaiiStateInfo
  (String hiStateId, String hiStatePassword) throws Exception {
    String dueDateInfo = "";
    String eachBookInfo = "";
    try {
      Hashtable<String, String> bookInfo = new Hashtable<String, String>();
      WebConversation conversation = this.loginToHawaiiStateLibrary(hiStateId, hiStatePassword);
      WebResponse response = conversation.getCurrentPage();
      WebLink link = response.getLinkWith("Items Out");
      link.click();
      response = conversation.getCurrentPage();
      if (response.getText().contains("Checked Out: 0")) {
        return bookInfo;      
      }
       
      else {
        WebTable targetTable = response.getTableStartingWith("Title");
        for (int i = 1; i < targetTable.getRowCount(); i++) {
          dueDateInfo = targetTable.getCellAsText(i, 2);
          eachBookInfo = targetTable.getCellAsText(i, 0).replaceAll("\n"," "); 
          bookInfo.put(eachBookInfo, dueDateInfo);
        }
        return bookInfo;
      }
      //boolean noBooksOut = response.getText().contains("Checked Out: 0");
      
      //(noBooksOut) ? "No items checked out" : "At least one item checked out.";
    }
    catch (Exception e) {
      throw new Exception("Error getting Hawaii State Library info", e);
    }
  }
  
  /**
   * Checks user command arguments and calls methods depends on the arguments.
   * 
   * @param args The arguments user provided
   * @throws Exception If problems occur accessing the library sites. 
   */
  public void argCheck(String[] args) throws Exception {
    String uhId = "";
    String uhLastName = "";
    String stateId = "";
    String lastPhoneNumber = "";   
    String sortOption = "";
    int withinDays = 0;
    String emailAccount = "";
    String smtpServer = "";    
    for (int i = 0; i < args.length; i++) {
      if ("-uhm".equals(args[i])) {
        uhLibrary = true;
        uhId = args[i + 1];
        uhLastName = args[i + 2];
        if (i + 3 < args.length) {
          i = i + 3;
        }       
      }
      if ("-hsl".equals(args[i])) {
        hsLibrary = true;
        stateId = args[i + 1];
        lastPhoneNumber = args[i + 2];
        if (i + 3 < args.length) {
          i = i + 3;
        }
      }
      if ("-sort".equals(args[i])) {
        sort = true;
        if ("library".equals(args[i + 1])) {
          sortOption = "library";
          if (i + 2 < args.length) {
            i = i + 2;
          }
        }
        else if ("duedate".equals(args[i + 1])) {
          sortOption = "duedate";
          if (i + 2 < args.length) {
            i = i + 2;
          }
        }
        else {
          System.out.println("Please provide correct sort option: library or duedate");
          sort = false;
        }
      }
      if ("-within".equals(args[i])) {
        within = true;
        withinDays = Integer.parseInt(args[i + 1]);
        if (i + 2 < args.length) {
          i = i + 2;
        }
      }
      if ("-console".equals(args[i])) {
        console = true;
        if (i + 1 < args.length) {
          i = i + 1;
        }
      }
      if ("-email".equals(args[i])) {
        email = true;
        emailAccount = args[i + 1];
        smtpServer = args[i + 2];
        if (i + 3 < args.length) {
          i = i + 3;
        }
      }
      if ("-wakeup".equals(args[i])) {
        wakeupValue = Double.parseDouble(args[i + 1]);
        if (i + 2 < args.length) {
          i = i + 2;
        }
      }
      
    }
    if (!console && !email) {
      System.out.println("Please provide either -console or -email option.");
      return;
    }
    if (!sort) {
      sort = true;
      sortOption = "library";
    }
    if (uhLibrary) {
      uhTable = getUhInfo(uhId, uhLastName);
    }
    if (hsLibrary) {
      hsTable = getHawaiiStateInfo(stateId, lastPhoneNumber);
    }
    if (within && withinDays > 0) {
      Calendar myCalendar = Calendar.getInstance();
      int dueYear = 0;
      int dueMonth = 0;
      int dueDate = 0;
      int todayDate = myCalendar.get(Calendar.DATE);
      int todayMonth = myCalendar.get(Calendar.MONTH) + 1;
      int todayYear = myCalendar.get(Calendar.YEAR);
      Iterator<?> it = uhTable.entrySet().iterator();
      ArrayList<String> removeList = new ArrayList<String>();
      while (it.hasNext()) {
        String element = (String)it.next();
        dueMonth = Integer.parseInt((uhTable.get(element)).substring(0, 2));
        dueDate = Integer.parseInt((uhTable.get(element)).substring(3, 5));
        dueYear = Integer.parseInt((uhTable.get(element)).substring(6, 8));
        if ((todayMonth == dueMonth) && ((todayYear - 2000) == dueYear) && 
            dueDate >= todayDate + withinDays) {          
          removeList.add(element);          
        }        
      }
      for (int i = 0; i < removeList.size(); i++) {
        uhTable.remove(removeList.get(i));  
      }
      removeList.clear();
      it = hsTable.entrySet().iterator();
      while (it.hasNext()) {
        String element = (String)it.next();
        dueMonth = Integer.parseInt((hsTable.get(element)).substring(0, 2));
        dueDate = Integer.parseInt((hsTable.get(element)).substring(3, 5));
        dueMonth = Integer.parseInt((hsTable.get(element)).substring(6, 10));

        if ((todayMonth == dueMonth) && (todayYear == dueYear) && 
            dueDate >= todayDate + withinDays) {
          removeList.add(element);          
        }
      } 
      for (int i = 0; i < removeList.size(); i++) {
        hsTable.remove(removeList.get(i));  
      }
    }
    if (sort && console) {
      if ("duedates".equals(sortOption)) {       
        System.out.println("");
      }
      else {
        System.out.println("Hawaii State Library System:");
        msgTxt = msgTxt + "Hawaii State Library System: \n";
        if (hsTable.isEmpty()) {
          System.out.println("No books Checked Out\n");
          msgTxt = msgTxt + "No books Checked Out\n";
        }
        else {
          Enumeration<String> e = hsTable.keys();
          while (e.hasMoreElements()) {
            String element = e.nextElement();
            msgTxt = msgTxt + hsTable.get(element) + " " + element + "\n";
            System.out.println(hsTable.get(element) + " " + element);
          }  
        }
        
        System.out.println("\nUH Manoa Library System:");
        msgTxt = msgTxt + "\nUH Manoa Library System:\n";
        Enumeration<String> e = uhTable.keys();
        while (e.hasMoreElements()) {
          String element = e.nextElement();
          msgTxt = msgTxt + uhTable.get(element) + " " + element + "\n";
          System.out.println(uhTable.get(element) + " " + element);
        }
      }
    }
    if (sort && email) {
      Properties props = new Properties();
      props.put("mail.smtp.host", smtpServer);
      Session session = Session.getInstance(props, null);
      try {
        // create a message
        Message msg = new MimeMessage(session);
        msg.setFrom(new InternetAddress("duedates-green-discuss@googlegroups.com"));
        InternetAddress[] address = {new InternetAddress(emailAccount)};
        msg.setRecipients(Message.RecipientType.TO, address);
        msg.setSubject("DueDates Green - Email Notification");
        msg.setSentDate(new Date());
        // If the desired charset is known, you can use
        // setText(text, charset)
        msg.setText(msgTxt);        
        Transport.send(msg);
      } 
      catch (MessagingException mex) {
        System.out.println("\n--Exception handling in msgsendsample.java");
      }
    }
    
  }
  
  /**
   * The main class illustrates the use of this code to login in systems. 
   * 
   * @param params Four strings: uhID, uhLastName, hiStateId, hiStatePassword.
   * @throws Exception If problems occur accessing the library sites. 
   */
  public static void main(String[] params) throws Exception {
    DueDates dueDates = new DueDates();
    dueDates.argCheck(params);
    dueDates.param = params;
    if (dueDates.wakeupValue > 0) { 
      Timer timer = new Timer(); 
      Calendar now = Calendar.getInstance(); 
      timer.schedule(dueDates, now.getTime(),  
          Long.valueOf(Math.round(1000 * 3600 * 24 * dueDates.wakeupValue))); 
    } 
    else { 
      dueDates.run(); 
    } 
  }

  @Override
  public void run() {
    DueDates dueDate = new DueDates();
    try {
      dueDate.argCheck(param);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    
  }
}

